package org.mockfu.junit;

import static org.mockfu.Exceptions.*;

import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;

import org.junit.Test;

public class ParallelExecutorTest
{

    @Test
    public void simple() throws Exception
    {
        final Semaphore task1Started = new Semaphore(0);
        final Semaphore task2Started = new Semaphore(0);

        Runnable task1 = new Runnable()
        {
            public void run()
            {
                task1Started.release();
                try
                {
                    task2Started.acquire();
                }
                catch (InterruptedException ex)
                {
                    throw undeclared(ex);
                }
            }
        };

        Runnable task2 = new Runnable()
        {
            public void run()
            {
                task2Started.release();
                try
                {
                    task1Started.acquire();
                }
                catch (InterruptedException ex)
                {
                    throw undeclared(ex);
                }
            }
        };

        ParallelExecutor.initialize(2);

        Future<?> future1 = ParallelExecutor.submit(task1);
        Future<?> future2 = ParallelExecutor.submit(task2);

        future1.get();
        future2.get();
    }

    @Test
    public void mutexes() throws Exception
    {
        final Semaphore task1Started = new Semaphore(0);
        final Semaphore task2Started = new Semaphore(0);
        final Semaphore task3Started = new Semaphore(0);

        Runnable task1 = new Runnable()
        {
            public void run()
            {
                task1Started.release();
                try
                {
                    task3Started.acquire();
                }
                catch (Exception ex)
                {
                    throw undeclared(ex);
                }
                if (task2Started.tryAcquire())
                    throw new AssertionError("task2 should not be started");
            }
        };

        Runnable task2 = new Runnable()
        {
            public void run()
            {
                task2Started.release();
            }
        };

        Runnable task3 = new Runnable()
        {
            public void run()
            {
                task3Started.release();
                Thread.yield();
                try
                {
                    task2Started.acquire();
                }
                catch (InterruptedException ex)
                {
                    throw undeclared(ex);
                }
            }
        };

        ParallelExecutor.initialize(3);

        Future<?> future1 = ParallelExecutor.submit(task1, "foo", "bar");
        task1Started.acquire();
        Future<?> future2 = ParallelExecutor.submit(task2, "bar");
        Future<?> future3 = ParallelExecutor.submit(task3, "qaz");

        future1.get();
        future2.get();
        future3.get();
    }
}
